package arcomage;

import java.util.*; // for Lists

/** This is an abstract class for an Arcomage player.
 *  @author Joshua Barnes
 *  @version 13th December 2009
 */
public abstract class AmPlayer
{
    public static final int maxHandSize=6;
    private String name;
    private List<AmCard> hand;
    private int tower;
    private int wall;
    private int magic;
    private int gems;
    private int quarry;
    private int bricks;
    private int zoo;
    private int beasts;

    /** Constructor which sets initial values using an AmRules set
     *  @param nameIn the name for the player. This should be unique.
     *  @param rulesIn the game ruleset
     */
    public AmPlayer(String nameIn, AmRules rulesIn)
    {
        name = nameIn;
        wall   = rulesIn.initialWall;
        tower  = rulesIn.initialTower;
        gems   = rulesIn.initialGems;
        bricks = rulesIn.initialBricks;
        beasts = rulesIn.initialBeasts;
        quarry = rulesIn.initialQuarry;
        magic  = rulesIn.initialMagic;
        zoo    = rulesIn.initialZoo;
        hand = new ArrayList<AmCard>();
    }
    /** Constructor which sets initial magic, zoo & quarry to 3
     *  @param nameIn the name for the player. This should be unique.
     *  @param wallIn the player's starting wall height
     *  @param towerIn the player's starting tower height
     */
    public AmPlayer(String nameIn, int wallIn, int towerIn)
    {
        name = nameIn;
        wall = wallIn;
        tower = towerIn;
        gems = 0;
        bricks = 0;
        beasts = 0;
        quarry = 3;
        magic = 3;
        zoo = 3;
        hand = new ArrayList<AmCard>();
    }
    /** Constructor which sets equal initial values for magic, zoo & quarry
     *  @param nameIn the name for the player. This should be unique.
     *  @param wallIn the player's starting wall height
     *  @param towerIn the player's starting tower height
     *  @param additivesIn the value to which the player's starting magic,
     *         quarry and zoo are set
     */
    public AmPlayer(String nameIn, int wallIn, int towerIn, int additivesIn)
    {
        name   = nameIn;
        wall   = wallIn;
        tower  = towerIn;
        gems   = 0;
        bricks = 0;
        beasts = 0;
        quarry = additivesIn;
        magic  = additivesIn;
        zoo    = additivesIn;
        hand = new ArrayList<AmCard>();
    }
    /** Constructor giving individual control over magic, zoo & quarry values
     *  @param nameIn the name for the player. This should be unique.
     *  @param wallIn the player's starting wall height
     *  @param towerIn the player's starting tower height
     *  @param magicIn the player's starting magic
     *  @param quarryIn the player's starting quarry
     *  @param zooIn the player's starting zoo
     */
    public AmPlayer(String nameIn, int wallIn, int towerIn, int quarryIn, int magicIn, int zooIn)
    {
        name   = nameIn;
        wall   = wallIn;
        tower  = towerIn;
        gems   = 0;
        bricks = 0;
        beasts = 0;
        quarry = quarryIn;
        magic  = magicIn;
        zoo    = zooIn;
        hand = new ArrayList<AmCard>();
    }
    public final String toString()
    {
        return "(" + getName() + ", tower="+tower+", wall="+wall+")\n";
    }
    public final int hashCode()
    {    // derive hashcode from the hashcode of the name string
        return this.getName().hashCode();
    }
    /** Deals damage first to a player's wall, then any excess damage to the
     *  player's tower*/
    public final void damage(int damageIn)
    {
        if (damageIn > wall)
        { //any damage not taken up by the wall will be taken by the tower.
            damageTower(damageIn-wall);
        }
        // damage the wall too
        damageWall(damageIn);
    }
    /** Deals damage only to the player's wall. Excess damage is disregarded.*/
    public final void damageWall(int damageIn)
    {
        wall -= damageIn;
        if (wall < 0)
        {
            wall = 0;
        }
    }
    /** Deals damage only to the player's tower. Excess damage is disregarded.*/
    public final void damageTower(int damageIn)
    {
        tower -= damageIn;
        if (tower < 0)
        {
            tower = 0;
        }
    }
    public final void growWall(int growthIn)
    {
        wall += growthIn;
    }
    public final void growTower(int growthIn)
    {
        tower += growthIn;
    }
    public String getName()
    {
        return name;
    }
    /** @return the player's new beasts value
     *  @param beastsIn how much to add to the player's beasts
     */
    public final int addBeasts(int beastsIn)
    {
        beasts += beastsIn;
        return beasts;
    }
    /** @return the player's new zoo value
     *  @param zooIn how much to add to the player's zoo
     */
    public final int addZoo(int zooIn)
    {
        zoo += zooIn;
        return zoo;
    }
    /** @return the player's new gems value
     *  @param gemsIn how much to add to the player's gems
     */
    public final int addGems(int gemsIn)
    {
        gems += gemsIn;
        return gems;
    }
    /** @return the player's new magic value
     *  @param magicIn how much to add to the player's magic
     */
    public final int addMagic(int magicIn)
    {
        magic += magicIn;
        return magic;
    }
    /** @return the player's new bricks value
     *  @param bricksIn how much to add to the player's bricks
     */
    public final int addBricks(int bricksIn)
    {
        bricks += bricksIn;
        return bricks;
    }
    /** @return the player's new quarry value
     *  @param quarryIn how much to add to the player's quarry
     */
    public final int addQuarry(int quarryIn)
    {
        quarry += quarryIn;
        return quarry;
    }
    public final int getWall()
    {
        return wall;
    }
    public final int getTower()
    {
        return tower;
    }
    public final int getBeasts()
    {
        return beasts;
    }
    public final int getZoo()
    {
        return zoo;
    }
    public final int getGems()
    {
        return gems;
    }
    public final int getMagic()
    {
        return magic;
    }
    public final int getBricks()
    {
        return bricks;
    }
    public final int getQuarry()
    {
        return quarry;
    }
    /** Reduces the player's beasts.
     *  @param beastsIn how much to remove from the player's beasts
     *  @return the player's new beasts value
     */
    public final int depleteBeasts(int beastsIn)
    {
        beasts -= beastsIn;
        if (beasts < 0)
        {
            beasts = 0;
        }
        return beasts;
    }
    /** Reduces the player's zoo.
     *  @param zooIn how much to remove from the player's zoo
     *  @return the player's new zoo value
     */
    public final int depleteZoo(int zooIn)
    {
        zoo -= zooIn;
        if (zoo < 0)
        {
            zoo = 0;
        }
        return zoo;
    }
    /** Reduces the player's gems.
     *  @param gemsIn how much to remove from the player's gems
     *  @return the player's new gems value
     */
    public final int depleteGems(int gemsIn)
    {
        gems -= gemsIn;
        if (gems < 0)
        {
            gems = 0;
        }
        return gems;
    }
    /** Reduces the player's magic.
     *  @param magicIn how much to remove from the player's magic
     *  @return the player's new magic value
     */
    public final int depleteMagic(int magicIn)
    {
        magic -= magicIn;
        if (magic < 0)
        {
            magic = 0;
        }
        return magic;
    }
    /** Reduces the player's bricks.
     *  @param bricksIn how much to remove from the player's bricks
     *  @return the player's new bricks value
     */
    public final int depleteBricks(int bricksIn)
    {
        bricks -= bricksIn;
        if (bricks < 0)
        {
            bricks = 0;
        }
        return bricks;
    }
    /** Reduces the player's quarry.
     *  @param quarryIn how much to remove from the player's quarry
     *  @return the player's new quarry value
     */
    public final int depleteQuarry(int quarryIn)
    {
        quarry -= quarryIn;
        if (quarry < 0)
        {
            quarry = 0;
        }
        return quarry;
    }
    /** Returns a copy of the player's hand. Note that these cards must be
     *  destroyed when finished with, rather than sent to a discard pile or
     *  other hand.
     *  @return a copy of the player's hand
     */
    public final List<AmCard> viewHand()
    {
        List<AmCard> retList = new ArrayList<AmCard>();
        /* AmCard objects are immutable, so we can simply add the existing
           * cards.*/
        for (AmCard currentCard: hand)
        {
            retList.add(currentCard);
        }

        return retList;
    }
    /** discards a card from the player's hand.
     *  @param discardIndexIn the list index of the card to discard
     *  @return the card discarded (to be added to a discard pile etc.)
     */
    public final AmCard discardCard(int discardIndexIn)
    {
        AmCard retCard = hand.get(discardIndexIn);
        hand.set(discardIndexIn,(AmCard) null);
        return retCard;
    }
    /** Returns a list containing the player's hand, and then empties it. */
    public final List<AmCard> returnHand()
    {
        List<AmCard> retList = viewHand();
        hand.clear();
        return retList;
    }
    /** Adds a card to the player's hand
     *  @return true if card added successfuly, false if there was no room for
     *          it in the player's hand
     */
    public final boolean pickUpCard(AmCard cardIn)
    {
        if (hand.size() == maxHandSize)
        {    // couldn't add card
            return false;
        }
        else
        {
            hand.add(cardIn);
            return true;
        }
    }
    /** Adds multiple cards to the player's hand
     *  @return true if all cards were added successfuly, false if there wasn't
     *          enough room in the player's hand.
     */
    public final boolean pickUpCards(List<AmCard> cardsIn)
    {
        boolean addedSuccessfully = true;
        while (!cardsIn.isEmpty() && addedSuccessfully)
        {
            addedSuccessfully = pickUpCard(cardsIn.remove(0));
        }
        return addedSuccessfully;
    }
    /** Returns the number of cards in the player's hand. */
    public final int handSize()
    {
        return hand.size();
    }
}
